package com.maybach.web.controller.product;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.audi.dubbo.api.brand.BrandService;
import com.audi.dubbo.api.brand.vos.BrandVo;
import com.audi.dubbo.api.brand.vos.SeriesVo;
import com.audi.dubbo.api.common.Result;
import com.audi.dubbo.api.item.intf.B2BCarService;
import com.audi.dubbo.api.item.intf.SynonymService;
import com.audi.dubbo.api.item.request.B2BCarRequest;
import com.audi.dubbo.api.item.request.SynonymRequest;
import com.audi.dubbo.api.item.response.impl.B2BCar;
import com.audi.dubbo.api.item.response.impl.BaseValue;
import com.audi.dubbo.api.item.response.impl.SynonymVo;
import com.audi.dubbo.api.search.SearchItemService;
import com.audi.dubbo.api.search.vos.SearchForm;
import com.audi.dubbo.api.search.vos.SearchResult;
import com.audi.dubbo.api.search.vos.SearchResultVo;
import com.google.common.collect.Lists;
import com.maybach.common.model.OperateLogDO;
import com.maybach.component.city.CityData;
import com.maybach.component.city.domain.City;
import com.maybach.core.ao.OperateLogAO;
import com.maybach.core.form.product.ProductEditForm;
import com.maybach.core.form.product.ProductQueryForm;
import com.maybach.core.form.product.SynonymForm;
import com.maybach.dubbo.api.model.OperateLogModel;
import com.maybach.util.ImgUrlUtil;
import com.maybach.util.PriceUtil;
import com.maybach.util.query.support.PageResult;

import libs.fastjson.com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

/**
 * Created by wenhua on 16/2/1.
 */
@Controller
@RequestMapping("/product")
@Slf4j
public class ProductListController {

	@Autowired
	private SearchItemService searchItemService;

	@Autowired
	private B2BCarService carService;

	@Autowired
	private BrandService brandService;

	@Autowired
	private SynonymService synonymService;

	@Autowired
	private OperateLogAO oplogAO;

	@RequestMapping(value = "/synonymList.htm")
	public void synonymList(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model,
			@RequestParam(required = false, value = "brandId") Long brandId,
			@RequestParam(required = false, value = "seriesId") Long seriesId,
			@RequestParam(required = false, value = "synonym") String synonym,
			@RequestParam(required = false, value = "current_page") Integer currentPage) {
		if (currentPage == null || currentPage == 0) {
			currentPage = 1;
		}
		try {
			List<BrandVo> brands = brandService.getAllBrand();
			model.addAttribute("brands", brands);
			if (brandId != null) {
				model.addAttribute("seriesList", brandService.getAllSeriesByBrandId(brandId));
			}
			SynonymRequest query = new SynonymRequest();
			query.setBrandId(brandId);
			query.setSeriesId(seriesId);
			query.setSynonymStr(synonym);
			int pageSize = 20;
			query.setStart(pageSize * (currentPage - 1));
			query.setPageSize(pageSize);
			Result<List<SynonymVo>> synonymResult = synonymService.getSynonymList(query);
			PageResult<SynonymVo> pageResult = new PageResult<SynonymVo>();
			pageResult.setPageSize(pageSize);
			pageResult.setPageNo(currentPage);
			if (synonymResult != null && synonymResult.isSuccess()) {
				model.addAttribute("synonyms", synonymResult.getData());
				pageResult.setResult(synonymResult.getData());
				pageResult.setTotalCount(synonymResult.getTotal());
			} else {
				log.error("Search fail.\nQueryForm is " + JSON.toJSONString(productQueryForm));
				pageResult.setTotalCount(0);
			}
			model.addAttribute("pageResult", pageResult);
			model.addAttribute("brandId", brandId);
			model.addAttribute("seriesId", seriesId);
			model.addAttribute("synonym", synonym);
		} catch (Exception e) {
			log.error("Exception happens.", e);
		}
	}

	@RequestMapping(value = "/synonymEdit.htm")
	public void synonymInfo(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model,
			@RequestParam(required = false, value = "synonym_id") @NotNull Long synonymId) {
		try {
			if (synonymId != null) {
				Result<SynonymVo> result = synonymService.getSingleSynonym(synonymId);
				if (result != null && result.isSuccess() && result.getData() != null) {
					SynonymVo synonym = result.getData();
					model.addAttribute("brands", brandService.getAllBrand());
					model.addAttribute("seriesList", brandService.getAllSeriesByBrandId(synonym.getBrandId()));
					model.addAttribute("synonym", synonym);
				} else {
					log.error("Query synonym fail.\nSynonymId is " + synonymId);
				}
			} else {
				model.addAttribute("brands", brandService.getAllBrand());
			}
		} catch (Exception e) {
			log.error("Exception happens. Query synonym fail.\nSynonymId is " + synonymId, e);
		}
	}

	@RequestMapping(value = "/carList.htm")
	public String list(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model,
			@RequestParam(required = false, value = "current_page") Integer currentPage,
			@RequestParam(required = false, value = "account") String account,
			@RequestParam(required = false, value = "model_name") String modelName,
			@RequestParam(required = false, value = "configure") String configure,
			@RequestParam(required = false, value = "remark") String remark) {
		if (currentPage == null || currentPage == 0) {
			currentPage = 1;
		}
		SearchForm searchForm = new SearchForm();
		searchForm.setSortType(3);
		int pageSize = 20;
		searchForm.setStart(pageSize * (currentPage - 1));
		searchForm.setPageSize(pageSize);
		searchForm.setModelStr(modelName);
		searchForm.setConfigure(configure);
		searchForm.setRemark(remark);
		searchForm.setAccount(account);
		SearchResult<List<SearchResultVo>> searchResult = searchItemService.b2bCarSearch(searchForm);

		List<SearchResultVo> carList = searchResult.getSearchResult();
		model.addAttribute("carList", carList);

		PageResult<SearchResultVo> pageResult = new PageResult<SearchResultVo>();
		pageResult.setPageSize(pageSize);
		pageResult.setPageNo(currentPage);
		pageResult.setTotalCount(searchResult.getTotal());
		pageResult.setResult(carList);
		model.addAttribute("modelName", modelName);
		model.addAttribute("configure", configure);
		model.addAttribute("remark", remark);
		model.addAttribute("account", account);
		model.addAttribute("pageResult", pageResult);
		return "/product/carList";
	}

	@RequestMapping(value = "/carEdit.htm")
	public void carInfo(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model,
			@RequestParam(required = false, value = "car_id") @NotNull Long carId) {
		try {
			Result<B2BCar> result = carService.querySingleCar(carId);
			if (result != null && result.isSuccess() && result.getData() != null) {
				B2BCar car = result.getData();
				ProductEditForm form = new ProductEditForm();
				form.setSpec(car.getSpec());
				form.setType(car.getType());
				form.setModelId(car.getModelId());
				form.setModelStr(car.getModelName());
				form.setBrandId(car.getBrandId());
				form.setSeriesId(car.getSeriesId());
				form.setOuterColorId(car.getOuterId());
				form.setInnerColorId(car.getInnerId());
				form.setFacadeStr(car.getOuterColorName());
				form.setTrimStr(car.getInnerColorName());
				form.setPrice(
						String.valueOf((-1 == car.getSellerPrice()) ? -1 : PriceUtil.formatCNYW(car.getSellerPrice())));
				form.setFuel(car.getFuel());
				form.setBenchMark(car.getBenchmark());
				form.setQuantity(car.getQuantity());
				form.setFrameNo(car.getCarUnique());
				form.setCarStatus(car.getCarStatus());
				form.setFormalityId(car.getFormalitiesStatus());
				form.setCustomFormality(car.getCustomFormality());
				form.setAreaId((null == car.getCarArea()) ? null : Integer.valueOf(car.getCarArea()));
				form.setArea(car.getCustomArea());
				form.setInsurance(car.getInsurance());
				form.setConfigure(car.getConfigure());
				form.setRemark(car.getRemark());
				form.setImgUrl(car.getImgUrl());
				form.setImgUrls(ImgUrlUtil.parseList(car.getImgUrl()));
				String cityStr = car.getSendCity();
				if (StringUtils.isNoneBlank(cityStr)) {
					if (cityStr.split(";").length == 4) {
						String[] cityInfo = cityStr.split(";");
						form.setProvinceId(Integer.valueOf(cityInfo[2]));
						form.setCityId(Integer.valueOf(cityInfo[3]));
						model.addAttribute("cities", CityData.getCity(form.getProvinceId()));
					} else if (cityStr.split(";").length == 2) {
						String[] cityInfo = cityStr.split(";");
						form.setProvinceId(Integer.valueOf(cityInfo[1]));
					}
				}
				model.addAttribute("brands", brandService.getAllBrand());
				model.addAttribute("series", brandService.getSeriesByBrandId(car.getBrandId()));
				model.addAttribute("models", brandService.getModelsBySeriesId(car.getSeriesId()));
				Result<Map<String, List<BaseValue>>> colorResult = carService.getTrimAndFacade(car.getSeriesId());
				if (colorResult.isSuccess()) {
					Map<String, List<BaseValue>> colorMap = colorResult.getData();
					model.addAttribute("facadeColors", colorMap.get("facade"));
					model.addAttribute("trimColors", colorMap.get("trim"));
				}
				model.addAttribute("form", form);
				model.addAttribute("provinces", CityData.getProvince());
				model.addAttribute("areas", CityData.getAreaList());
				model.addAttribute("carId", carId);
			} else {
				log.error("Query car fail.\nCarId is " + carId);
			}
		} catch (Exception e) {
			log.error("Exception happens. Query car fail.\nCarId is " + carId, e);
		}
	}

	@RequestMapping(value = "/opDetail.htm")
	public void opInfo(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model,
			@RequestParam(required = false, value = "oplog_id") @NotNull Long oplogId) {
		OperateLogModel opLog = new OperateLogModel();
		opLog.setId(oplogId);
		try {
			PageResult<OperateLogDO> queryRes = oplogAO.queryOperateLog(opLog);
			if (queryRes != null && CollectionUtils.isNotEmpty(queryRes.getResult())
					&& queryRes.getResult().size() == 1) {
				OperateLogDO opLogDO = queryRes.getResult().get(0);
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String createLogTime = sdf.format(opLogDO.getGmtCreate());
				model.addAttribute("op", opLogDO);
				model.addAttribute("createTime", createLogTime);
			} else {
				log.error("Query op log fail.\nId is " + oplogId);
			}
		} catch (Exception e) {
			log.error("Query op log error.\nId is " + oplogId);
		}
	}

	@RequestMapping(value = "/opList.htm")
	public void opList(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model,
			@RequestParam(required = false, value = "current_page") Integer currentPage,
			@RequestParam(required = false, value = "start_time") String startTime,
			@RequestParam(required = false, value = "end_time") String endTime) {
		OperateLogModel opLog = new OperateLogModel();

		if (StringUtils.isNoneBlank(startTime)) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			try {
				opLog.setStartDate(sdf.parse(startTime + " 00:00:00"));
			} catch (ParseException e) {
				log.error("Parse start time error.\nStartTime is " + startTime);
			}
		}
		if (StringUtils.isNoneBlank(endTime)) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			try {
				opLog.setEndDate(sdf.parse(endTime + " 00:00:00"));
			} catch (ParseException e) {
				log.error("Parse end time error.\nEndTime is " + endTime);
			}
		}
		opLog.setPageNo((currentPage == null) ? 1 : currentPage);
		opLog.setPageSize(20);
		if (StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime)) {
			model.addAttribute("startTime", startTime);
			model.addAttribute("endTime", endTime);
		}
		try {
			PageResult<OperateLogDO> queryRes = oplogAO.queryOperateLog(opLog);
			if (queryRes != null && CollectionUtils.isNotEmpty(queryRes.getResult())) {
				model.addAttribute("opList", queryRes.getResult());
				model.addAttribute("pageResult", queryRes);
			} else {
				log.error("Query op log fail.\nPage is " + currentPage);
			}
		} catch (Exception e) {
			log.error("Query op log error.\nPage is " + currentPage);
		}
	}

	@RequiresAuthentication
	@ResponseBody
	@RequestMapping(value = "/addSeriesSynonym.json", method = RequestMethod.POST)
	public boolean addSeriesSynonym(@Valid SynonymForm form, HttpServletRequest request) {
		SynonymRequest synonReq = new SynonymRequest();
		synonReq.setSynonymId(form.getId());
		synonReq.setSeriesId(form.getSeriesId());
		synonReq.setBrandId(form.getBrandId());
		synonReq.setAlias(form.getAlias());
		synonReq.setSynonymStr(form.getDataValue());
		synonReq.setType("series");
		try {
			Result<Boolean> addResult = synonymService.addSynonym(synonReq);
			if (addResult != null && addResult.isSuccess()) {
				return addResult.getData();
			} else {
				log.error("Edit synonym error.\nParam is " + JSON.toJSONString(form));
				return false;
			}
		} catch (Exception e) {
			log.error("Exception happens.\nParam is " + JSON.toJSONString(form), e);
			return false;
		}
	}

	@RequiresAuthentication
	@ResponseBody
	@RequestMapping(value = "/editSynonym.json", method = RequestMethod.POST)
	public boolean editSynonym(@Valid SynonymForm form, HttpServletRequest request) {
		SynonymRequest synonReq = new SynonymRequest();
		synonReq.setSynonymId(form.getId());
		synonReq.setSeriesId(form.getSeriesId());
		synonReq.setBrandId(form.getBrandId());
		synonReq.setAlias(form.getAlias());
		try {
			Result<Boolean> editResult = synonymService.editSynonym(synonReq);
			if (editResult != null && editResult.isSuccess()) {
				return editResult.getData();
			} else {
				log.error("Edit synonym error.\nParam is " + JSON.toJSONString(form));
				return false;
			}
		} catch (Exception e) {
			log.error("Exception happens.\nParam is " + JSON.toJSONString(form), e);
			return false;
		}
	}

	@RequiresAuthentication
	@ResponseBody
	@RequestMapping(value = "/doEdit.json", method = RequestMethod.POST)
	public boolean editCar(@Valid ProductEditForm form, HttpServletRequest request) {
		B2BCarRequest carReq = new B2BCarRequest();
		BeanUtils.copyProperties(form, carReq);
		Long price = (StringUtils.isEmpty(form.getPrice())) ? -1L : PriceUtil.parseCentFromW(form.getPrice());
		carReq.setPrice(price);
		List<String> imgUrls = Lists.newArrayList(form.getImgUrl().split(";"));
		carReq.setImgUrl(ImgUrlUtil.mergeList(imgUrls));
		String sendCity;
		if (form.getProvinceId() != null && form.getCityId() == null) {
			sendCity = CityData.getProvinceById(form.getProvinceId()).getName() + ";" + form.getProvinceId() + ";";
		} else if (form.getProvinceId() != null && form.getCityId() != null) {
			sendCity = CityData.getProvinceById(form.getProvinceId()).getName() + ";"
					+ CityData.getCityById(form.getCityId()).getName() + ";" + form.getProvinceId() + ";"
					+ form.getCityId() + ";";
		} else {
			sendCity = null;
		}
		carReq.setSendCity(sendCity);
		carReq.setStatus(form.getCarStatus());
		try {
			Result<Boolean> result = carService.editCar(carReq, form.getCarId());
			if (result.isSuccess()) {
				if (result.getData()) {
					Thread.sleep(1000L);
					return true;
				} else {
					return false;
				}
			} else {
				log.error("Update fail.\nParam is " + JSON.toJSONString(form));
				return false;
			}
		} catch (Exception e) {
			log.error("Exception happens.\nParam is " + JSON.toJSONString(form), e);
			return false;
		}
	}

	@ResponseBody
	@RequestMapping(value = "/getSeries.json", method = RequestMethod.POST)
	public List<SeriesVo> getSeriesList(@NotNull long brandId) {
		try {
			return brandService.getAllSeriesByBrandId(brandId);
		} catch (Exception e) {
			log.error("Get seriesList error.\nBrandId is " + brandId, e);
			return Lists.newArrayList();
		}
	}

	@ResponseBody
	@RequestMapping(value = "/exportCar.json", method = RequestMethod.POST)
	public Long exportCar() {
		try {
			Result<Long> result = carService.exportCarsAsyn(Arrays.asList(2, 3, 4, 5, 6, 7), "brand");
			if (result.isSuccess()) {
				return result.getData();
			} else {
				log.error("Export fail.");
				return -1L;
			}
		} catch (Exception e) {
			log.error("Exception happens.", e);
			return -1L;
		}
	}

	@ResponseBody
	@RequestMapping(value = "/getCities.json", method = RequestMethod.POST)
	public List<City> getCities(@NotNull String province) {
		List<City> cities = CityData.getCityByProvinceName(province);
		return cities;
	}

	@RequestMapping(value = "/batchDeleteCar.htm")
	public void batchDeleteCar(@Valid ProductQueryForm productQueryForm, BindingResult bindingResult, ModelMap model) {
	}

	@ResponseBody
	@RequestMapping(value = "/batchDeleteCar.json", method = RequestMethod.POST)
	public boolean batchDeleteCar(@NotNull Integer specId, @NotNull String deleteTime) {
		B2BCarRequest request = new B2BCarRequest();
		request.setSpec((specId == -1) ? null : specId);
		try {
			if (StringUtils.isNoneBlank(deleteTime)) {
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				request.setDeleteTime(sdf.parse(deleteTime + " 00:00:00"));
			} else {
				request.setDeleteTime(new Date());
			}
			Result<Boolean> deleteRes = carService.batchDeleteCar(request);
			if (deleteRes != null && deleteRes.isSuccess()) {
				return deleteRes.getData();
			} else {
				log.warn("Delete fail.\nSpec is " + specId);
				return false;
			}
		} catch (Exception e) {
			log.error("Exception happens. Delete false.\nId is " + specId, e);
			return false;
		}
	}

	@ResponseBody
	@RequestMapping(value = "/synonymList/delete_synonym.json", method = RequestMethod.POST)
	public boolean deleteSynonym(@NotNull long synonymId) {
		SynonymRequest request = new SynonymRequest();
		request.setSynonymId(synonymId);
		request.setIsDeleted(1);
		try {
			Result<Boolean> result = synonymService.editSynonym(request);
			if (result != null && result.isSuccess()) {
				Thread.sleep(1000L);
				return result.getData();
			} else {
				log.error("Delete fail.\nId is " + synonymId);
				return false;
			}
		} catch (Exception e) {
			log.error("Exception happens. Delete false.\nId is " + synonymId, e);
			return false;
		}
	}

	@ResponseBody
	@RequestMapping(value = "/getSynonym.json", method = RequestMethod.POST)
	public SynonymVo getSynonymBySeries(@NotNull long seriesId) {
		try {
			Result<SynonymVo> result = synonymService.getSynonymBySeriesId(seriesId);
			if (result != null && result.isSuccess()) {
				Thread.sleep(1000L);
				return result.getData();
			} else {
				log.error("Search fail.\nSeriesId is " + seriesId);
				return null;
			}
		} catch (Exception e) {
			log.error("Exception happens. Delete false.\nSeriesId is " + seriesId, e);
			return null;
		}
	}

	@ResponseBody
	@RequestMapping(value = "/carList/delete_car.json", method = RequestMethod.POST)
	public boolean deleteCar(@NotNull long carId) {
		B2BCarRequest request = new B2BCarRequest();
		request.setIsDeleted(1);
		try {
			Result<Boolean> result = carService.editCar(request, carId);
			if (result != null && result.isSuccess()) {
				Thread.sleep(1000L);
				return result.getData();
			} else {
				log.error("Delete fail.\nCarId is " + carId);
				return false;
			}
		} catch (Exception e) {
			log.error("Exception happens. Delete false.\nCarId is " + carId, e);
			return false;
		}
	}

}
